//=============================================================================
// PNT.fx by Bart Uyttenhove 2009
//
// 
//=============================================================================
#include "lighthelper.fx"

#define FOGMODE_NONE    0
#define FOGMODE_LINEAR  1
#define FOGMODE_EXP     2
#define FOGMODE_EXP2    3
#define E 2.71828

RasterizerState Cull
{
	CullMode = BACK;
};

SamplerState samLinear
{
    Filter = ANISOTROPIC;
    AddressU = Wrap;// of Mirror of Clamp of Border
    AddressV = Wrap;// of Mirror of Clamp of Border
};
SamplerState samPoint
{
    Filter = MIN_MAG_MIP_POINT;
    AddressU = Clamp;// of Mirror of Clamp of Border
    AddressV = Clamp;// of Mirror of Clamp of Border
};
SamplerState samAnisotropic
{
	Filter = ANISOTROPIC ;
    AddressU = Border;// of Mirror of Clamp of Border
    AddressV = Border;// of Mirror of Clamp of Border
    BorderColor = float4(0.0f,0.0f,1.0f,1.0f);
};
SamplerState gTriLinearSam
{
	Filter = MIN_MAG_MIP_LINEAR;
	AddressU = Wrap;
	AddressV = Wrap;
};

cbuffer cbPerObject
{
	float4x4 gWVP;
	float4x4 gWorld;
	float4x4 gReflectionWorldViewProj;
	float gWaveLength;
	float gWaveHeight;
	float3 gCamPos;
	float gTime;
	float3 gWindDirection;
	float gWindForce;
	Light2 gLight;
	int      g_fogMode = FOGMODE_LINEAR;
	float    g_fogStart = 50.0f;
    float    g_fogEnd = 300.0f;
    float    g_fogDensity = 0.05f;
	float    g_fogMaxHeight = 0.05f;
    float4   g_fogColor = float4(0.7f,1.0f,1.0f,1);
};

Texture2D Texture;
Texture2D Refraction;
Texture2D Reflection;
Texture2D waterBumpMap;
// we gebruiken deze structs omdat ze oa de leesbaarheid verhogen
// POSITION, COLOR en NORMAL zijn semantics en komen overeen met

// de InputLayout
struct VS_IN
{
	float3 Pos : POSITION;
	float3 Norm : NORMAL;
    float2 Tex : TEXCOORD0;
};
struct VS_OUT
{
	float4 Position						: POSITION;
	float4 PosW							: TEXCOORD0;
	float3 Norm							: NORMAL;
	float4 ReflectionMapSamplingPos		: TEXCOORD1;
	float2 BumpMapSamplingPos			: TEXCOORD2;
	float4 RefractionMapSamplingPos		: TEXCOORD3;
	float4 Position3D					: TEXCOORD4;
};

VS_OUT VS(	VS_IN vIn)
{
	VS_OUT Output = (VS_OUT)0;
	//Wind
	//float2 moveVector = float2(0, gTime*gWindForce);

	float3 windDir = normalize(gWindDirection);    
	float3 perpDir = cross(gWindDirection, float3(0,1,0));

	float ydot = dot(vIn.Tex, gWindDirection.xz);
	float xdot = dot(vIn.Tex, perpDir.xz);
	float2 moveVector = float2(xdot, ydot);

	moveVector.y += gTime*gWindForce;    
	//Output.BumpMapSamplingPos = moveVector/xWaveLength; 

    Output.Position = mul(float4(vIn.Pos, 1.0f) , gWVP);
	Output.PosW = mul(float4(vIn.Pos, 1.0f) , gWorld);
	Output.BumpMapSamplingPos = moveVector/gWaveLength;
	Output.ReflectionMapSamplingPos = mul(float4(vIn.Pos, 1.0f), gReflectionWorldViewProj);
	Output.RefractionMapSamplingPos = mul(float4(vIn.Pos, 1.0f) , gWVP);
	Output.Position3D = mul(float4(vIn.Pos, 1.0f) , gWorld);
	Output.Norm = mul(vIn.Norm, (float3x3)gWorld);
    return Output;
}
float CalcFogFactor( float d )
{
    float fogCoeff = 1.0;
    
    if( FOGMODE_LINEAR == g_fogMode )
    {
        fogCoeff = (g_fogEnd - d)/(g_fogEnd - g_fogStart);
    }
    else if( FOGMODE_EXP == g_fogMode )
    {
        fogCoeff = 1.0 / pow( E, d*g_fogDensity );
    }
    else if( FOGMODE_EXP2 == g_fogMode )
    {
        fogCoeff = 1.0 / pow( E, d*d*g_fogDensity*g_fogDensity );
    }
    
    return clamp( fogCoeff, 0, 1 );
}
float4 PSAnisotropic(	VS_OUT pIn) : SV_Target
{  

	float fog = CalcFogFactor(length(pIn.PosW - gCamPos));

    float2 ProjectedTexCoords;
    ProjectedTexCoords.x = pIn.ReflectionMapSamplingPos.x/pIn.ReflectionMapSamplingPos.w/2.0f + 0.5f;
    ProjectedTexCoords.y = -pIn.ReflectionMapSamplingPos.y/pIn.ReflectionMapSamplingPos.w/2.0f + 0.5f;    

	float4 bumpColor = waterBumpMap.Sample(gTriLinearSam, pIn.BumpMapSamplingPos);
	float2 perturbation = gWaveHeight*(bumpColor.rg - 0.5f)*2.0f;
	float2 perturbatedTexCoords = ProjectedTexCoords + perturbation;
    float4 ReflectiveColor = Reflection.Sample( gTriLinearSam, perturbatedTexCoords ).rgba;   
     
	//Refraction
	float2 ProjectedRefrTexCoords;
	ProjectedRefrTexCoords.x = pIn.RefractionMapSamplingPos.x/pIn.RefractionMapSamplingPos.w/2.0f + 0.5f;
	ProjectedRefrTexCoords.y = -pIn.RefractionMapSamplingPos.y/pIn.RefractionMapSamplingPos.w/2.0f + 0.5f;    
	float2 perturbatedRefrTexCoords = ProjectedRefrTexCoords + perturbation;    

	float4 RefractiveColor = Refraction.Sample( gTriLinearSam, perturbatedRefrTexCoords ).rgba;

	float3 eyeVector = normalize(gCamPos - pIn.Position3D);
	float3 normalVector = (bumpColor.rbg-0.5f)*2.0f;

	float fresnelTerm = dot(eyeVector, normalVector);    
	float4 combinedColor = lerp(ReflectiveColor, RefractiveColor, fresnelTerm);
     
	float4 dullColor = float4(0.3f, 0.3f, 0.5f, 1.0f);

	float3 reflectionVector = reflect(-gLight.dir, normalVector);

	float specular = max(dot(normalize(reflectionVector), normalize(eyeVector)), 0.0f);

	specular = pow(specular, 256);      
	
	float4 Color = lerp(combinedColor, dullColor, 0.2f);
	float4 SpecColor = float4(1.0f, 1.0f, 1.0f, 1.0f);

	Color.rgb += specular*SpecColor;

	float4 finalcolor = fog * Color + (1.0 - fog)*g_fogColor;

	return finalcolor;
	//Light calculations
    //float4 Diff = lerp(combinedColor, dullColor, 0.2f);
//
	//float4 spec = float4(1.0f, 1.0f, 1.0f, 1.0f);
	//// Map [0,1] --> [0,256]
	//spec.a *= 256.0f;
//
	////soms wordt door interpolatie de lengte van de vector aangepast.
   	//pIn.Norm=-normalize(pIn.Norm);
//
	//float3 normalLight = (bumpColor.rbg-0.5f)*2.0f;
	//normalLight = -normalize(normalLight);
	//// Compute the lit color for this pixel.
    //SurfaceInfo v = {pIn.Position3D.xyz, normalLight, Diff, spec};
	//float3 litColor = ParallelLightNoShadow(v, gLight, gCamPos);
//
	//return float4(litColor, 1.0f);
}

technique10 Water
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, PSAnisotropic() ) );
		SetRasterizerState(Cull);
  }
}